package spe.xml;

import java.beans.PropertyChangeEvent;
import java.util.Iterator;
import java.util.Map;

import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import spe.model.notation.Link;
import spe.model.spem.MethodContentPackage;
import spe.model.spem.MethodPlugin;
import spe.model.spem.ProcessPackage;
import spe.model.spem.SPEMElement;

public class MethodPluginAdapter extends SPEXmlAdapter 
{
	private static String[] CHILD_ELEMENTS = {
		"base-plugin",
		"method-content-package",
		"process-package"
	};
	
	public MethodPluginAdapter() 
	{
		// TODO Auto-generated constructor stub
	}
	
	@Override
	protected String[] getChildElements()
	{
		return CHILD_ELEMENTS;
	}

	
	protected void initialize()
	{
		super.initialize();
		MethodPlugin mp = (MethodPlugin) getSemanticElement();
		if(mp != null)
		{
			setAttribute("id", mp.getId());
			setAttribute("name", mp.getName());
		}
		//System.out.println(String.format("[MethodPluginAdapter] initialize() %s to %s", getSemanticElement(), this));
	}
	
	public void initialize(SPEMElement element)
	{
		//System.out.println(String.format("[MethodPluginAdapter] initialize(%s) to %s", element, this));
		//super.initialize(element);
		semanticElement = element;
	
		NodeList nodeList = getNode().getChildNodes();
		for (int i = 0; i < nodeList.getLength(); i++) 
		{
			if(!(nodeList.item(i).getNodeName().equals("base-plugin")))
			{
				SPEXmlAdapter childDomAdapter = getAdapter(nodeList.item(i));
				if (childDomAdapter != null && !"#comment".equals(childDomAdapter.getNode().getNodeName()))
					doModelAdd(childDomAdapter);
			}
			else
			{
				addBasePlugin(((Element)nodeList.item(i)).getAttribute("id"));
			}
			
		}
		//System.out.println(String.format("[SPEXmlAdapter] Adapter: %s, node: %s", this, jpdlElement));
		register();
		
		MethodPlugin mp = (MethodPlugin) semanticElement;
		if(mp != null)
		{
			mp.setId(getAttribute("id"));
			mp.setName(getAttribute("name"));
			mp.addPropertyChangeListener(this);
		}
	}

	@Override
	protected void doModelUpdate(String name, String newValue) 
	{
		// TODO Auto-generated method stub

	}

	@Override
	protected void doModelAdd(SPEXmlAdapter child) 
	{
		// TODO Auto-generated method stub
		String type = child.getElementType();
		SPEMElement childElement = null; //createSemanticElementFor(child);
		
		MethodPlugin mp = (MethodPlugin) this.getSemanticElement();
		
		if("method-content-package".equals(type))
		{
			Element e = (Element)child.getNode();
			String id = e.getAttribute("id");
			if(mp.getOwnedMethodContentPackages() != null)
			{
				Iterator<MethodContentPackage> iter = mp.getOwnedMethodContentPackages().iterator();
				while(iter.hasNext())
				{
					MethodContentPackage mcp = iter.next(); 
					if(id.equals((mcp.getId())))
					{
						childElement = mcp;
						break;
					}
				}
			}
		}
		else
		if("process-package".equals(type))
		{
			Element e = (Element)child.getNode();
			String id = e.getAttribute("id");
			if(mp.getOwnedProcessPackages() != null)
			{
				Iterator<ProcessPackage> iter = mp.getOwnedProcessPackages().iterator();
				while(iter.hasNext())
				{
					ProcessPackage mcp = iter.next(); 
					if(id.equals((mcp.getId())))
					{
						childElement = mcp;
						break;
					}
				}
			}
		}
		
		if(childElement == null)
		{
			childElement = createSemanticElementFor(child);
			mp.addChildElement(childElement);
		}
		
		child.initialize(childElement);
	}

	@Override
	protected void doModelRemove(SPEXmlAdapter child) {
		// TODO Auto-generated method stub

	}

	@Override
	protected void doPropertyChange(PropertyChangeEvent event) 
	{
		String propertyName = event.getPropertyName();
		if(propertyName.equals("BasePlugin"))
		{
			MethodPlugin basePlugin = (MethodPlugin) event.getNewValue();
			
			if(basePlugin != null)
			{
				addBasePlugin(basePlugin);
				//System.out.println(String.format("[MethodPluginAdapter] Set base plugin"));
			}
		}
		else if( propertyName.equals("name") || propertyName.equals("id") )
		{
			setAttribute(propertyName, event.getNewValue().toString());
		}
	}
	
	private void addBasePlugin(MethodPlugin basePlugin)
	{
		Element bpnode = node.getOwnerDocument().createElement("base-plugin");
		bpnode.setAttribute("id", basePlugin.getId());
		
		if(isEmpty())
		{
		}
		node.insertBefore(bpnode, null);
	}
	
	protected void addBasePlugin(String basePluginId)
	{
		Map<SPEMElement, SPEXmlAdapter> map = factory.getRegisteredAdapters(MethodPlugin.class);
		Iterator<SPEMElement> keys = map.keySet().iterator();
		
		while(keys.hasNext())
		{
			MethodPlugin mp = (MethodPlugin) keys.next();
			
			if(basePluginId.equals(mp.getId()))
			{
				((MethodPlugin)semanticElement).setBasePlugin(mp);
				//set Link
				Link l = new Link();
				l.setSource(mp);
				l.setTarget((MethodPlugin)semanticElement);
				mp.addLeavingEdge(l);
				((MethodPlugin)semanticElement).addArrivingEdge(l);
			}
		}
	}
	
	protected void register()
	{
		Map<SPEMElement, SPEXmlAdapter> map = factory.getRegisteredAdapters(MethodPlugin.class);
		Iterator<SPEMElement> keys = map.keySet().iterator();
		while(keys.hasNext())
		{
			MethodPlugin mp = (MethodPlugin) keys.next();
			SPEXmlAdapter adap = map.get(mp);
			NodeList bases = ((Element)adap.getNode()).getElementsByTagName("base-plugin");
			
			if( mp.getBasePlugin() == null)
			{
				//System.out.println(String.format("[MethodPluginAdapter] BASE PLUGIN SET TO %s; num of base %d", mp, bases.getLength()));
				for(int i=0;i<bases.getLength();i++)
					if(bases.item(i).getNodeType() != Node.TEXT_NODE)
					{
						Element baseDomElement = (Element) bases.item(i);
						String id = baseDomElement.getAttribute("id");
						if(id.equals(semanticElement.getId()))
						{
							mp.setBasePlugin((MethodPlugin) semanticElement);
							//System.out.println(String.format("[MethodPluginAdapter] BASE PLUGIN SET"));
						}
					}
			}
			
		}//end while
		super.register();
	}

}
